/*
 * Copyright (c) 2006 Karlan Thomas Mitchell<karlanmitchell@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *         This product includes software developed by
           Karlan Thomas Mitchell<karlanmitchell@gmail.com>
 * 4. Neither Karlan Thomas Mitchell nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY KARLAN THOMAS MITCHELL AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.


What is this:
---------------------------
	The only files you should look at are
	  (1) This
	  (2) crash_agent.c  - Crash Agent, runs your program(or crash_test default)
	  (2) crash_test.c   - Program which should SEGFAULT.
	  (2) FILES.txt      - Descriptions of some stuff included

	if problems arise
	  (1) edit configure if resonable


How to use/build:
---------------------------
	You want to open up crash_agent.c, 
        and edit some of the variables around
        there.  They are at the very top.

	Next type './configure.sh', it will guess some things, next
        you should have a crash_agent.exe to use with your program!
	
	crash_agent.exe will run exe_cmd variable in the C program through
	system() in Unix or hidden CreateProcess in windows.

	Windows users may run compile.bat, make sure you have Mingw or Dev-CPP.


Variables to edit:
---------------------------
	exe_cmd:           Command in current directory to run through debugger.
	email_server:      SMTP server which doesn't require AUTH.
	developer_email:   E-Mail to deliever bug report.
	crash_agent_email: Usually made up email address, make sure it doesn't get
                           ignored by server because of length, or characters.
	email_subject:     Subject of E-Mail to developer.
	lame_exit_cmp:     Your program should output this line just before every exit,
			   If GDB isn't present, this is used to determine a crash!  
	message_text:      Pango HTML string to be displayed in by the crash agent upon
			   Your program crashing.



In crash_agent.c:
---------------------------

	char * exe_cmd             = {"DGAF.exe"};
	char * email_server        = {"smtp.comcast.net"};
	char * developer_email     = {"karlanmitchell@comcast.net"};
	char * crash_agent_email   = {"dgaf_crash_agent@random.com"};
	char * lame_exit_cmp       = {"DGAF SUCCESSFUL EXIT."};

	char * message_text = {"<span size=\"x-large\"><b>DGAF has crashed!</b></span>\n\n<b>Please contribute to the development of\nthis program by submitting a bug report!\n\nYour privacy is respected and \nno sensitive information is ever sent.</b>"};






--------------------

If you love the program, or hate it, E-Mail me at karlanmitchell@gmail.com

 */
#include <gtk/gtk.h>
#include "portable_socket.h"
#include "smtp.h"
#include <time.h>
#ifdef WIN32
       #include "pthread.h"
#else
     #include <sys/utsname.h>
     #include <pthread.h>
#endif




/*Please repsect MY privacy*/

char * exe_cmd             = {"server.exe"}; /*Do not use directory information*/
char * email_server        = {"smtp.comcast.net"};
char * developer_email     = {"karlanmitchell@comcast.net"};
char * crash_agent_email   = {"dgaf_crash_agent@random.com"};
char * email_subject       = {"DGAF Crash Report"};


/*This text is searched for in the output of the program if GDB/DBX doesn't exist,
  if this text is not found, your program is assumed crashed (if exited)*/
char * lame_exit_cmp       = {"P2P SERVER: SUCCESSFUL EXIT."};

char * message_text = {"<span size=\"x-large\"><b>Cliqueshare Server has crashed!</b></span>\n\n<b>Please contribute to the development of\nthis program by submitting a bug report!\n\nYour privacy is respected and \nno sensitive information is ever sent.</b>"};






/*I wouldn't recommend editing anything below this, however this program is very small. */






/*DO NOT EDIT THE DEBUGGER COMMANDS (unless you know what your doing)*/



/*GDB, this is always tried first!*/
char * gdbcommand_buf      = {"run\nbacktrace full"};
/*For Solaris, they have dbx, and its pretty similar, I'll just support it! :-D*/
char * dbxcommand_buf      = {"run ; where ; dump ; quit"};

char * divider = "\n-------------------------------------------------------------\n\0";

GtkWidget * MainWindow;
GtkWidget * StatusWindow;

GtkWidget * StatusLabel;
GtkWidget * MessageLabel;
GtkWidget * blanklabel;
GtkWidget * EmailLabel;
GtkWidget * EmailEntry;
GtkWidget * WhyLabel;
GtkWidget * WhyTextView;
GtkWidget * SendButton;
GtkWidget * WelcomeButton;
GtkWidget * ViewEmailButton;
GtkWidget * ViewEmailWindow;
GtkWidget * vbox;



int waiting_for_debugger = 1;
char  gdbcommand_file [PATH_MAX];
char  backtrace_file [PATH_MAX];



int is_lame_report = 0;


int crashed = 0;
int filed_report = 0;

void * email_crash_report(void * args);




void crash_main_destroy();
void crash_main_destroy(){
     gtk_widget_destroy(MainWindow);

      /*
     if(crashed == 1 && filed_report == 0){
                     filed_report = 1;
                     email_crash_report(NULL);
                     }
    
     */
     
     printf("(%d) remove\n",remove(backtrace_file));
     gtk_exit(0);  
     exit(0);
     }


void cat_uname_to_file(char * filename){
	}


void * email_crash_report(void * args){
     const gchar * tmp_from_email = gtk_entry_get_text( GTK_ENTRY(EmailEntry) );
     GtkTextBuffer * why_crashed_buf = gtk_text_view_get_buffer ( GTK_TEXT_VIEW ( WhyTextView ) );
     gchar * why_crashed;
     
     char  from_email[1024];
     if(strlen(tmp_from_email) == 0)
                               strcpy(from_email, developer_email);
     else
         strlcpy(from_email, tmp_from_email, 1024);
     
     
     GtkTextIter start;
      GtkTextIter end;

     gtk_text_buffer_get_start_iter (why_crashed_buf, &start);
     gtk_text_buffer_get_end_iter (why_crashed_buf, &end);

     /* Get the entire buffer text. */
     why_crashed = gtk_text_buffer_get_text (why_crashed_buf, &start, &end, FALSE);

     
     FILE * bt_file = fopen(backtrace_file, "a");
     

     if(is_lame_report){
     	fwrite(divider, 1, strlen(divider), bt_file);
     	fwrite("NOTES: ", 1, strlen("NOTES: "), bt_file);
     	fwrite("This is a lame (non-gdb) crash report", 1, strlen("This is a lame (non-gdb) crash report"), bt_file);
        }


     if(strcasecmp(from_email, developer_email) != 0){
                            fwrite(divider, 1, strlen(divider), bt_file);
                            fwrite("FROM: ", 1, strlen("FROM: "), bt_file);
                            fwrite(from_email, 1, strlen(from_email), bt_file);
     }
     
     if(strlen(why_crashed) > 1){
                            fwrite(divider, 1, strlen(divider), bt_file);
                            fwrite("DESCRIPTION:\n", 1, strlen("DESCRIPTION:\n"), bt_file);
                            fwrite(why_crashed, 1, strlen(why_crashed), bt_file);
     }


     fwrite(divider, 1, strlen(divider), bt_file);
     fwrite("OPERATING SYSTEM:\n", 1, strlen("OPERATING SYSTEM:\n"), bt_file);
     #ifdef LINUX
     fwrite("Linux", 1, strlen("Linux"), bt_file);
     #elif MACOSX
     fwrite("Mac OS X", 1, strlen("Mac OS X"), bt_file);
     #elif WIN32
     fwrite("Microsoft Windows", 1, strlen("Microsoft Windows"), bt_file);
     #elif FREEBSD
     fwrite("FreeBSD", 1, strlen("FreeBSD"), bt_file);
     #elif OPENBSD
     fwrite("OpenBSD", 1, strlen("OpenBSD"), bt_file);
     #elif NETBSD
     fwrite("NetBSD", 1, strlen("NetBSD"), bt_file);
     #elif SUNOS
     fwrite("Solaris SunOS", 1, strlen("Solaris SunOS"), bt_file);
     #else
     fwrite("Unknown", 1, strlen("Unknown"), bt_file);
     #endif

     
     #ifndef WIN32
     struct utsname uname_data;
     uname(&uname_data);
     fwrite(" (", 1, 2, bt_file);
     fwrite(uname_data.sysname, 1, strlen(uname_data.sysname), bt_file);
     fwrite(" ", 1, 1, bt_file);
     fwrite(uname_data.nodename, 1, strlen(uname_data.nodename), bt_file);
     fwrite(" ", 1, 1, bt_file);
     fwrite(uname_data.release, 1, strlen(uname_data.release), bt_file);
     fwrite(" ", 1, 1, bt_file);
     fwrite(uname_data.version, 1, strlen(uname_data.version), bt_file);
     fwrite(" ", 1, 1, bt_file);
     fwrite(uname_data.machine, 1, strlen(uname_data.machine), bt_file);
     fwrite(")", 1, 1, bt_file);
     #endif
     fclose(bt_file);

     send_email_file(email_server, email_subject, crash_agent_email, NULL, developer_email, backtrace_file);
     
     g_free(why_crashed);
     
     
  //   gtk_widget_destroy(StatusWindow);
  //   gtk_widget_destroy(StatusLabel);
    /* 
     gtk_widget_destroy(MessageLabel);
     gtk_widget_destroy(blanklabel);
     gtk_widget_destroy(EmailLabel);
     gtk_widget_destroy(EmailEntry);
     gtk_widget_destroy(WhyLabel);
     gtk_widget_destroy(WhyTextView);
     gtk_widget_destroy(SendButton);
     gtk_widget_destroy(vbox);
     
     
     MessageLabel = gtk_label_new("");
     gtk_label_set_markup (GTK_LABEL (MessageLabel), "<span size=\"x-large\"><b>Thank you for your help!</b></span>");
     vbox          = gtk_vbox_new(0, 0);
     
     g_signal_connect(G_OBJECT(MainWindow), "destroy", crash_main_destroy, NULL);
     g_signal_connect(G_OBJECT(MainWindow), "clicked", crash_main_destroy, NULL);
     

    
     gtk_box_pack_start (GTK_BOX (vbox), MessageLabel,   FALSE, FALSE, 0);
     gtk_container_add (GTK_CONTAINER (MainWindow), vbox);
	 
     gtk_widget_show(MessageLabel);
     gtk_widget_show(vbox);
  //  gtk_widget_show(MainWindow);
     */
    
    crash_main_destroy();
    
     pthread_exit(NULL);
     }




void *status_email(void * args){
     int counter = 0;
     while(1){
              if(counter % 2 == 1)
                         gtk_label_set_text(GTK_LABEL(StatusLabel), "E-Mailing Bug Report. . . ");
              else
                         gtk_label_set_text(GTK_LABEL(StatusLabel), "E-Mailing Bug Report . . .");
             gtk_widget_draw(StatusLabel, NULL);
              sleep(1);
              counter++;
              }
     }



void spawn_email(){
     if(filed_report != 0)
                     return;
     filed_report = 1;
     
     StatusWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
     StatusLabel = gtk_label_new("E-Mailing Bug Report. . .");
     
    gtk_window_set_title (GTK_WINDOW (StatusWindow), "(Please Wait...) Crash Agent"); 
    gtk_container_set_border_width(GTK_CONTAINER (StatusWindow), 15);
    
	gtk_container_add (GTK_CONTAINER (StatusWindow), StatusLabel);
     
    gtk_widget_show(StatusWindow);
    gtk_widget_show(StatusLabel);
    
     
	pthread_t email_pthread_t;
	
	pthread_create(&email_pthread_t, NULL, &status_email, NULL);
	pthread_detach(email_pthread_t);

	pthread_create(&email_pthread_t, NULL, &email_crash_report, NULL);
	pthread_detach(email_pthread_t);


}

int gdb_exist(){
        char gdb_command[4096];
        #ifdef WIN32
        snprintf(gdb_command, 4096, "gdb --version > nul");
        #else
        snprintf(gdb_command, 4096, "gdb --version > /dev/null");
        #endif
        int success;
	if(system(gdb_command) == 0)
		return 1;
	return 0;
	}

int dbx_exist(){
        char gdb_command[4096];
        #ifndef WIN32
        int success = 0;

        snprintf(gdb_command, 4096, "/opt/SUNWspro/bin/dbx -c \"quit\" -V > /dev/null");
	if(system(gdb_command) == 0)
		success = 1;

	return success;
	#else 
		return 0;
        #endif
	}

void * program_debugger(void * args){
     
     /*
     BOOL CreateProcess(

    LPCTSTR lpApplicationName,	// pointer to name of executable module 
    LPTSTR lpCommandLine,	// pointer to command line string
    LPSECURITY_ATTRIBUTES lpProcessAttributes,	// pointer to process security attributes 
    LPSECURITY_ATTRIBUTES lpThreadAttributes,	// pointer to thread security attributes 
    BOOL bInheritHandles,	// handle inheritance flag 
    DWORD dwCreationFlags,	// creation flags 
    LPVOID lpEnvironment,	// pointer to new environment block 
    LPCTSTR lpCurrentDirectory,	// pointer to current directory name 
    LPSTARTUPINFO lpStartupInfo,	// pointer to STARTUPINFO 
    LPPROCESS_INFORMATION lpProcessInformation 	// pointer to PROCESS_INFORMATION  
   );*/
    
     char gdb_command[4096];
     #ifdef WIN32
     snprintf(gdb_command, 4096, "gdb.exe --batch --command=%s --nw --quiet --args %s", gdbcommand_file, exe_cmd);
     #else
     snprintf(gdb_command, 4096, "gdb --batch --command=%s --nw --quiet --args %s 2> /dev/stdout > %s ", gdbcommand_file, exe_cmd, backtrace_file);
     #endif



     if(gdb_exist() == FALSE){
	is_lame_report = 1;
	/*Test for DBX*/
	if(dbx_exist() == TRUE){
		/*Win32 should NEVER make it this far*/
     		snprintf(gdb_command, 4096, "echo quit | /opt/SUNWspro/bin/dbx -c \"%s\" %s 2> /dev/stdout > %s ", dbxcommand_buf, exe_cmd, backtrace_file);
 
	}
	else{
        	printf("Your system doesn't have GNU or DBX debugger, you must \ninstall one for the crash agent to be any bit useful!\n\n", gdb_command);
        	snprintf(gdb_command, 4096, "./%s > %s", exe_cmd, backtrace_file);
		}
	}

     printf("Running %s\n%s\n", exe_cmd, gdb_command);
      

int success;

#ifdef WIN32
    STARTUPINFO startupInfo;
    PROCESS_INFORMATION procInfo;
    SECURITY_ATTRIBUTES lpProcessAttributes;
    ZeroMemory( &lpProcessAttributes, sizeof(LPSECURITY_ATTRIBUTES) );
    lpProcessAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
    lpProcessAttributes.bInheritHandle = TRUE;
    lpProcessAttributes.lpSecurityDescriptor = NULL;
    
     HANDLE hFile = CreateFile(backtrace_file,GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,&lpProcessAttributes,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); 

    //GetStartupInfo(&startupInfo); 
    
    ZeroMemory( &procInfo, sizeof(PROCESS_INFORMATION) );
    ZeroMemory(&startupInfo,sizeof(STARTUPINFO));
    startupInfo.cb = sizeof(STARTUPINFO);
    startupInfo.dwFlags     = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    startupInfo.wShowWindow = SW_HIDE;	
    startupInfo.hStdOutput  = hFile;	
    startupInfo.hStdError   = hFile;
    

    success = CreateProcess(NULL,
			gdb_command,
			NULL, NULL, TRUE,
			0,
			NULL, NULL,
			&startupInfo,
			&procInfo);
			
     WaitForSingleObject(procInfo.hProcess, INFINITE);
     
     printf("(%d) CloseHandle\n",CloseHandle(hFile));
#else
success = system(gdb_command);
#endif     



     printf("(%d) %s finished.\n",success, exe_cmd);
     waiting_for_debugger = 0;
     }

int spawn_debugger(){
	pthread_t debugger_pthread_t;

	pthread_create(&debugger_pthread_t, NULL, &program_debugger, NULL);
	pthread_detach(debugger_pthread_t);

}




void view_crash_report(){
        ViewEmailWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        gtk_widget_set_size_request (ViewEmailWindow, 600, 400);
	
	GtkWidget * ScrolledWindow = gtk_scrolled_window_new(NULL, NULL);
	GtkWidget * report_buf = GTK_TEXT_BUFFER(gtk_text_buffer_new(NULL));
	GtkWidget * ReportTextView;
	GtkWidget * ReportOkButton = gtk_button_new_with_label("OK");
        
     	GtkWidget * reportvbox          = gtk_vbox_new(0, 0);
    
	off_t filesize = getfilesize(backtrace_file);
	char * filebuf = malloc((filesize + 1) * sizeof(char));


	FILE * fin = fopen(backtrace_file, "r");
	filebuf[filesize] = 0;
	fread(filebuf, 1, filesize, fin);

	gchar * new_buf = g_convert(filebuf, -1, "UTF-8", "ISO-8859-1", NULL, NULL, NULL);

	gtk_text_buffer_set_text(GTK_TEXT_BUFFER(report_buf), new_buf, strlen(new_buf));


	ReportTextView = gtk_text_view_new_with_buffer(GTK_TEXT_BUFFER(report_buf));
        gtk_widget_set_size_request (ReportTextView, 600, 340);
	gtk_text_view_set_editable(GTK_TEXT_VIEW(ReportTextView), 0);
	gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(ReportTextView), 0);

	fclose(fin);
	free(filebuf);
	
	gtk_container_add (GTK_CONTAINER (ScrolledWindow), ReportTextView);
        gtk_box_pack_start (GTK_BOX (reportvbox), ScrolledWindow,   FALSE, FALSE, 0);
        gtk_box_pack_start (GTK_BOX (reportvbox), ReportOkButton,   FALSE, FALSE, 0);
	gtk_container_add (GTK_CONTAINER (ViewEmailWindow), reportvbox);

 	g_signal_connect_swapped(G_OBJECT(ReportOkButton), "activate", G_CALLBACK(gtk_widget_destroy), ViewEmailWindow);
 	g_signal_connect_swapped(G_OBJECT(ReportOkButton), "clicked", G_CALLBACK(gtk_widget_destroy), ViewEmailWindow);
    
         gtk_widget_show(ReportOkButton);
         gtk_widget_show(reportvbox);
         gtk_widget_show(ScrolledWindow);
         gtk_widget_show(report_buf);
        gtk_widget_show(ReportTextView);
        gtk_widget_show(ViewEmailWindow);
	}



int main(int argc, char * argv[]){
    


    printf("Program Wrapper & Crash Reporter\n");
    printf("Karlan Thomas Mitchell (C) 2006\n\n");


     /*Get Temp Directory to store backtrace, and output*/

    char tmp_dir[PATH_MAX];
    GetTempPath(PATH_MAX, tmp_dir);

    srand(time(NULL));
    do{
    snprintf(backtrace_file, PATH_MAX, "%sbt%d.txt", tmp_dir, rand() % 1000);
    }while(is_file(backtrace_file));


    srand(time(NULL));
    do{
    snprintf(gdbcommand_file, PATH_MAX, "%sgdbcmd%d.txt", tmp_dir, rand() % 1000);
    }while(is_file(backtrace_file));
    
    FILE * gdbcommand_f = fopen(gdbcommand_file, "w");
    fwrite(gdbcommand_buf, 1, strlen(gdbcommand_buf), gdbcommand_f);
    fclose(gdbcommand_f);


    spawn_debugger();    
    
    while(waiting_for_debugger){sleep(1);}
    
    
    char line_buffer[50];
    
    if(is_lame_report == 1)
	crashed = 1;

    FILE * bt_fd = fopen(backtrace_file, "r");
    if(bt_fd == NULL)
	return 0;
    


    while(!feof(bt_fd)){
           freadline_r(bt_fd, line_buffer, 50);
           if(is_lame_report){
           	if(strncasecmp(line_buffer, lame_exit_cmp, strlen(lame_exit_cmp)) == 0){
                                       crashed = 0;
                                       break;
                                       }
	   }
	   else{
           	if(strncasecmp(line_buffer, "Program received signal", strlen("Program received signal")) == 0){
                                       crashed = 1;
                                       printf("Program has crashed!\n");
                                       break;
                                       }
           }
                                       
    }

    fclose(bt_fd);
    if(crashed == 0){
        printf("Program has exited successfully!\n");
     printf("(%d) remove\n",remove(backtrace_file));
        exit(0);
    }
        
    gtk_set_locale();
    gtk_init(&argc, &argv);
    psocket_environment_init(); 
    
    MainWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title (GTK_WINDOW (MainWindow), "Smart Crash Agent"); 
    gtk_container_set_border_width(GTK_CONTAINER (MainWindow), 10);
    
    MessageLabel = gtk_label_new("");
    char *markup;
    markup = g_markup_printf_escaped (message_text);
    gtk_label_set_markup (GTK_LABEL (MessageLabel), markup);
    g_free (markup);


    ViewEmailButton = gtk_button_new_with_label("View Crash Log");
    blanklabel = gtk_label_new("");
    EmailLabel = gtk_label_new("E-Mail Address (Optional):");
    EmailEntry = gtk_entry_new();
    SendButton = gtk_button_new_with_label("Send Bug Report!");
    WhyLabel = gtk_label_new("Explain what you where doing when the program crashed (Optional)\n");
    WhyTextView = gtk_text_view_new();
    gtk_widget_set_size_request (WhyTextView, 75, 75);

     vbox          = gtk_vbox_new(0, 0);
    
    gtk_box_pack_start (GTK_BOX (vbox), MessageLabel,   FALSE, FALSE, 0);
    gtk_box_pack_start (GTK_BOX (vbox), blanklabel,   FALSE, FALSE, 0);

    gtk_box_pack_start (GTK_BOX (vbox), ViewEmailButton,   FALSE, FALSE, 0);
    gtk_box_pack_start (GTK_BOX (vbox), blanklabel,   FALSE, FALSE, 0);

    gtk_box_pack_start (GTK_BOX (vbox), EmailLabel,   FALSE, FALSE, 10);
    gtk_box_pack_start (GTK_BOX (vbox), EmailEntry,   FALSE, FALSE, 0);
    gtk_box_pack_start (GTK_BOX (vbox), WhyLabel,   FALSE, FALSE, 10);
    gtk_box_pack_start (GTK_BOX (vbox), WhyTextView,   FALSE, FALSE, 0);
    gtk_box_pack_start (GTK_BOX (vbox), SendButton,   FALSE, FALSE, 10);
	gtk_container_add (GTK_CONTAINER (MainWindow), vbox);

    
    g_signal_connect(G_OBJECT(ViewEmailButton), "clicked", view_crash_report, NULL);
    g_signal_connect(G_OBJECT(ViewEmailButton), "activate", view_crash_report, NULL);

    g_signal_connect(G_OBJECT(EmailEntry), "activate", spawn_email, NULL);
    g_signal_connect(G_OBJECT(SendButton), "clicked", spawn_email, NULL);
    g_signal_connect(G_OBJECT(MainWindow), "destroy", crash_main_destroy, NULL);
    
    gtk_widget_show(ViewEmailButton);
    gtk_widget_show(MainWindow);
    gtk_widget_show(MessageLabel);
    gtk_widget_show(blanklabel);
    gtk_widget_show(EmailLabel);
    gtk_widget_show(EmailEntry);
    gtk_widget_show(SendButton);
    gtk_widget_show(WhyLabel);
    gtk_widget_show(WhyTextView);
    gtk_widget_show(vbox);
     
    
    gtk_main();
    
    return 0;
}
